#include <math.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "procmontiondection.h"

#define ONE_PIC_DIVIDE_NUM		4	// 一张图片从上到下平均分成4块分别检测灰度变化
#define CHECK_PIC_GRAY_NUM		4	// 检查当前图片和前三张图片两两之间平均灰度差值

// 移动侦测灵敏度，值越小越灵敏，本数值为实际场景中大量测试得到的经验值
static int gMotionDetectSensitivity = 4;


// 计算一帧图像的平均灰度
static int CalcAverageGray(unsigned char *img, int width, int height, unsigned int *pixel)
{
	int i = 0;
	int j = 0;
	unsigned int pix = 0;

	for(i = 0; i < height; i += 2) //每两行只计算一行
	{
		for(j = 0; j < width; j += 2) //每两列值计算一列
		{
			pix += *(img + i*width + j);
		}
		if(0 == ((i + 2) % (height/ONE_PIC_DIVIDE_NUM)))  //分别计算4块，缓存每一块的平均灰度值
		{
            //全部计算灰度和/像素点数
			pix = pix / ((width * height / 4) / ONE_PIC_DIVIDE_NUM);
            //缓存
			pixel[i / (height/ONE_PIC_DIVIDE_NUM)] = pix;
            //一块计算完成清零重新计算
			pix = 0;
			//PrintDebug("zuocs -----------pix %d = %d\n", i / (height/ONE_PIC_DIVIDE_NUM), pixel[i / (height/ONE_PIC_DIVIDE_NUM)]);
		}
	}

	return pix;
}


// img 原始灰度图像数据  
int ProcMotionDetection(int opType, unsigned char *img, int width, int height)
{
	int i = 0;
	int j = 0;
	int z = 0;
	unsigned int curGrayVal[ONE_PIC_DIVIDE_NUM] = { 0 };
	static int discardCount = 3; 
	static unsigned int count = 0;
	static unsigned int preGrayVal[CHECK_PIC_GRAY_NUM][ONE_PIC_DIVIDE_NUM] = { 0 };

    // 当连续提取人脸模板失败，重新进入移动侦测流程，复位计数器
	if(opType == OP_TYPE_CLEAR)
	{
		count = 0;
		discardCount = 3;
		memset(preGrayVal, 0, sizeof(preGrayVal));
		return 0;
	}
    
    //丢弃3帧图像，过滤由于开关灯图像剧烈变化导致误探测
	if (discardCount > 0)
	{
		discardCount--;
		return 0;
	}

	CalcAverageGray(img, width, height, curGrayVal);

	for (i = 0; i < ONE_PIC_DIVIDE_NUM; i++)
	{
		preGrayVal[count % CHECK_PIC_GRAY_NUM][i] = curGrayVal[i];
	}
	count++;

    //进入移动侦测后，缓存4帧以上图像平均灰度值
	if ((count >= CHECK_PIC_GRAY_NUM))
	{
        //计算当前帧与前面3帧图像的平均灰度差
		for (z = 0; z < ONE_PIC_DIVIDE_NUM; z++)
		{
			for (i = 0; i < CHECK_PIC_GRAY_NUM; i++)
			{
				for (j = 0; j < CHECK_PIC_GRAY_NUM; j++)
				{
                    //其中一个块灰度差大于等于灵敏度(4) 时，通知应用探测到物体靠近，开启近红外补光灯
					if ((abs((int)(preGrayVal[i][z] - preGrayVal[j][z])) >= gMotionDetectSensitivity))
					{
						return 1;
					}
				}
			}
		}
	}
	return 0;
}